package rekursion;

/* Dieses Programm berechnet vollständig geklammerte Ausdrücke
 * mit den vier Grundrechenarten. Beispiel
 * java BerechneKlammer "((12/(4+2))+(2*8))"
 * 18.0
 */
public class BerechneKlammer{
  protected static int pos;        // zeigt auf das nächste Zeichen
  protected static String eingabe; // die eingegebene Rechnung in Klammern

  public static void main(String[] args){
    eingabe=args[0];
    pos=0;// zeigt auf öffnende Klammer
    System.out.println(berechne());
  }

  /* gibt an, ob ein char in einem String enthalten ist
   */
  public static boolean oneOf(char c, String menge){
    for(int i=0; i<menge.length(); ++i)
      if(c==menge.charAt(i)) return true;
    return false;
  }

  /* wandelt den String ab pos so weit wie möglich in
   * eine Kommazahl um.
   */
  public static double getZahl(){
    int start=pos;
    // suche das Ende der Zahl, die bei pos beginnt
    while(!oneOf(eingabe.charAt(pos), "+-*/()")) pos++;
    return Double.parseDouble(eingabe.substring(start, pos));
  }

  /* rückt um ein Zeichen vor.
   */
  public static void weiter(){pos++;}

  /* gibt das aktuelle Zeichen zurück.
   */
  public static char aktuell(){return eingabe.charAt(pos);}

  //diese Methode sollten die Schüler alleine finden
  /* Ignoriert vorderstes Zeichen, weil es sicher eine '(' ist.
   * Holt dann einen Wert, ein Rechenzeichen und noch einen Wert
   * aus dem String (durch Aufruf von sich selbst).
   * Berechnet je nach Rechenzeichen das Ergebnis.
   * Ignoriert das nachfolgende Zeichen, weil es sicher eine ')' ist.
   * Aktuell ist dann also das Zeichen nach der schließenden Klammer
   * dieser Berechnung.
   * Gibt das Ergebnis zurück.
   */
  public static double berechne(){
    weiter();// die hier sicher stehende öffnende Klammer interessiert nicht
    double a, b;
    if(aktuell()=='(') a=berechne();
    else a=getZahl();
    char op=aktuell(); weiter();
    if(aktuell()=='(') b=berechne();
    else b=getZahl();
    weiter();// die hier sicher stehende schließende Klammer muss weg
    switch(op){
      case '+': a+=b; break;
      case '-': a-=b; break;
      case '*': a*=b; break;
      case '/': a/=b; break;
      default: a=Double.NaN;
    }
    return a;
  }
}
